#!/usr/bin/ruby

require "sqlite3"
require 'pp'
require File.dirname(__FILE__) + "/shared.rb"

DEBUG = false

NOISE_PROFILE = RAMO_HOME + "noise-profile"
NOISE_RED_AMT = 0.3

SOXI_DUR_RE = /^Duration\s*: ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9][0-9])/
SOXI_DUR_RE_IDX = 1


def log(s)
    puts "#{Time.now()} : #{s}\n"   if DEBUG
    f = File.new(DAEMON_LOG, 'a')
    f.write("#{Time.now()} : #{s}\n")
    f.close()
end

def time2fname_suf(t)
    year  = t.year.to_s
    month = pad2(t.month)
    mday  = pad2(t.mday)
    hour  = pad2(t.hour)
    min   = pad2(t.min)

    dir = "/#{year}/#{month}/#{mday}/"
    return dir, "#{dir}/#{hour}#{min}.#{AUD_FORMAT}"
end

def time_floor(t)
    lag = t.to_i % BLOCK_DUR
    return t - lag
end

# determines the actual length of a recording
def get_file_duration(fname)
    soxi_out = `soxi #{fname}`
    md = SOXI_DUR_RE.match(soxi_out)
    if md
        h,m,s = md[SOXI_DUR_RE_IDX].split(':')
    else
        log("warning: soxi duration regexp did not match: \"#{soxi_out}\"")
        return 0
    end
    return s.to_i + 60*m.to_i + 60*60*h.to_i
end

def db_exec(cmd)
    if DEBUG
        puts "db cmd = #{cmd}"
    else
        #puts "db cmd = #{cmd}"
        #puts "DBFILE = #{DB_FILE}"
        db = SQLite3::Database.new(DB_FILE)
        db.execute(cmd)
    end
end

def sh_exec(cmd)
    if DEBUG
        puts "sh cmd = #{cmd}"
    else
        #puts "sh cmd = #{cmd}"
        `#{cmd}`
    end
end

def rec()
    temp_dir = `mktemp -d`[0..-2]
    temp_fname = temp_dir + "/temp-rec.#{AUD_FORMAT}"
    
    # what to do if the daemon is quit partway through recording
    Signal.trap("QUIT") do
        log("caught signal QUIT - will delete temp recording and directory")
        sh_exec("rm #{temp_fname}")
        sh_exec("rmdir #{temp_dir}")
        exit(1)
    end
    log("about to start recording")
    
    start_t = Time.now()
    end_t = time_floor(start_t) + BLOCK_DUR + OVERLAP_DUR
    
    duration = end_t.to_i - start_t.to_i
    sh_exec( "rec -c 1 -r #{RATE} #{temp_fname}\
        trim 0 #{duration.to_f}  \
        silence -l 1 0 #{THRESHOLD}% -1 #{SILENCE_DUR.to_f} #{THRESHOLD}% \
        noisered #{NOISE_PROFILE} #{NOISE_RED_AMT.to_f} \
        >/dev/null 2>/dev/null" )
   
    dir_suf, fname_suf = time2fname_suf(start_t)
    fname = RECS_DIR + fname_suf
    
    # move file out of /tmp and remove temp_dir
    sh_exec("mkdir --parents #{RECS_DIR + dir_suf}")
    sh_exec("mv #{temp_fname} #{fname}")
    sh_exec("rmdir #{temp_dir}")
    
    log("recording complete, saved to #{fname}")
    return start_t, end_t, fname_suf
end

# adds a recording to the database
def db_store(start_t, end_t, fname_suf)
    row = []
    row[START_T_DBI]= start_t.to_i
    row[END_T_DBI]  = end_t.to_i
    row[ACT_LEN_DBI]= get_file_duration(RECS_DIR + fname_suf)
    row[WDAY_DBI]   = start_t.wday
    row[DTIME_DBI]  = start_t.hour*60*60 + start_t.min*60 + start_t.sec
    row[FNAME_DBI]  = "\"#{fname_suf}\""
    row[HAVE_F_DBI] = "1"
    
    log("storing #{fname_suf} to db")
    
    cmd = "INSERT INTO Recordings VALUES(#{row.join(", ")});"
    db_exec(cmd)

    log("db store complete for #{fname_suf}")
end

def rec_and_store
    start_t, end_t, fname_suf = rec()
    db_store(start_t, end_t, fname_suf)
end

def test
    puts "pretending to record"
    `sleep 5`
    puts "done with pretend recording"
end

def main
    while true
        log("recording cycle started")
        Thread.new { rec_and_store() }
        #thread = Thread.new { test() }
        
        next_t = time_floor(Time.now()) + BLOCK_DUR
        log("sleeping until #{next_t}")
        sleep(next_t.to_i - Time.now.to_i)
    end
end

if __FILE__ == $0
    log("starting recorder-daemon -------------------------------")
    main
end
